// 从json文件中读取数据
import 'dart:convert' show json;
import 'package:flutter/services.dart' show rootBundle, AssetBundle;
import 'dart:math' show Point;

/// 一个用于从JSON文件中读取坐标点数据的工具类
///
/// 该类提供了从指定JSON文件中读取特定类型的点数据列表的功能
/// 支持从AssetBundle或默认的rootBundle中加载数据
class GetPoints {
  final String filePath;
  final String billType;
  final AssetBundle? assetBundle;

  /// 创建一个GetPoints实例
  ///
  /// [billType] 要从JSON文件中获取的数据类型键名
  /// [filePath] JSON文件在assets中的路径
  /// [assetBundle] 可选的AssetBundle，默认为rootBundle
  GetPoints(this.billType, this.filePath, {this.assetBundle});

  /// 从JSON文件中读取点列表
  ///
  /// 返回一个包含Point对象的列表，每个Point包含x和y坐标
  /// 如果发生错误，会抛出异常，建议调用时使用try-catch处理
  Future<List<Point<double>>> jsonToPointList() async {
    // if (billType.isEmpty) {
    //   throw ArgumentError('billType cannot be empty');
    // }

    // if (filePath.isEmpty) {
    //   throw ArgumentError('filePath cannot be empty');
    // }

    try {
      // 使用提供的assetBundle或默认的rootBundle
      final bundle = assetBundle ?? rootBundle;
      final jsonString = await bundle.loadString(filePath);
      final data = json.decode(jsonString) as Map<String, dynamic>;

      // 检查billType是否存在
      if (!data.containsKey(billType)) {
        throw FormatException(
          'billType "$billType" not found in the JSON data',
        );
      }

      final pointMap = data[billType];

      // 验证数据类型
      if (pointMap is! List) {
        throw FormatException('Data for billType "$billType" must be a list');
      }

      return _convertToPoints(pointMap);
    } on FormatException catch (e) {
      throw Exception('JSON parsing error: ${e.message}');
    } catch (e) {
      throw Exception('Unexpected error: $e');
    }
  }

  /// 将动态列表转换为Point列表
  ///
  /// [pointMap] 包含点数据的动态列表，每个元素都是一个Map
  /// 返回一个包含Point对象的列表，每个Point包含x和y坐标
  /// 如果点数据格式错误，会抛出FormatException
  /// 每个点数据必须包含'x'和'y'属性，且值必须为数字类型
  List<Point<double>> _convertToPoints(List<dynamic> pointMap) {
    return List.generate(pointMap.length, (i) {
      final pointData = pointMap[i];

      // 验证点数据格式
      if (pointData is! Map ||
          !pointData.containsKey('x') ||
          !pointData.containsKey('y')) {
        throw FormatException(
          'Invalid point data at index $i: missing required x or y property',
        );
      }

      try {
        final x = (pointData['x'] as num).toDouble();
        final y = (pointData['y'] as num).toDouble();
        return Point<double>(x, y);
      } catch (e) {
        throw FormatException('Invalid numeric values at index $i: $e');
      }
    });
  }

  /// 静态方法：从JSON文件中获取点列表
  ///
  /// [billType] 要从JSON文件中获取的数据类型键名
  /// [filePath] JSON文件在assets中的路径
  /// [assetBundle] 可选的AssetBundle，默认为rootBundle
  /// 返回一个包含Point对象的列表，每个Point包含x和y坐标
  /// 如果发生错误，会抛出异常，建议调用时使用try-catch处理
  static Future<List<Point<double>>> fromJson(
    String billType,
    String filePath, {
    AssetBundle? assetBundle,
  }) async {
    final fetcher = GetPoints(billType, filePath, assetBundle: assetBundle);
    return fetcher.jsonToPointList();
  }
}
